API 접근 제어 우회

개요

원래 쿠버 API 서버만이 클러스터에서 다른 것들과 상호작용을 하는 유일한 컴포넌트다.
쿠버네티스는 허브앤스포크 패턴 방식이기 때문에 그렇다.
여기에서 쿠버네티스 감사승인 제어를 하게 되는데, 이것을 우회하는 방법이.. 있다!
이걸 잘 제한하는 것도 매우 중요한 사항이다.

정적 파드

kubelet이 자신의 노드에 직접적으로 실행하는 정적 파드는 api 서버로 관리되지 않는다.
쿠버네티스를 통해 정적 파드를 확인할 수 있는 것은 그저 kubelet이 mirror pod를 api에 제공해 보이도록 해주는 것일 뿐이다.
노드의 정적 파드의 양식을 저장하는 디렉토리에 쓰기 권한을 가진 공격자는 멋대로 정적 파드를 만들어버릴 수 있을 것이다.
(근데 그런 케이스가 얼마나..?)
정적 파드는 대부분의 다른 오브젝트에 접근할 수 없다.
그러나 이놈들이 위험한 이유는 hostPath와 같은 노드의 시스템 레벨의 권한을 획득할 수 있다는 것이다.
그리고 이건 그저 kubelet이 보여주는 것에 불과하다 했는데, 유효하지 않은 네임스페이스를 지정해버리면 그마저도 조회가 안 된다.
진짜? 그런게 만들어진다고?
정적 파드가 승인 제어에 실패하면 kubelet은 api 서버에 등록도 하지 않는데, 그럼에도 사실 파드는 노드에서 돌아간다.

완화책은 다음과 같다.

kubelet api

kubelet은 노드의 tcp 10250 포트에 http api를 노출한다.
이것은 컨트롤 플레인에서도 당연히 마찬가지인데, 이 api에 대한 직접적인 접근은 노드의 정보를 볼 수 있다.
돌아가는 파드의 정보, 로그, 컨테이너에 대한 명령 실행이 가능해진다.

쿠버네티스에서 노드 오브젝트에 대한 rbac 권한이 있으면 이 api를 쓸 수 있게 되는 것이다.
이건 kubelet 인가에서 자세히 보도록 한다.
https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/#kubelet-authorization

사실 kubelet api에 직접적으로 접근하면 감사나 승인 제어에 걸리지 않는다.
그래서 이 api 주소에 접근할 방법을 찾아낸 공격자는 해당 노드에 대한 정보를 마구 읽을 수 있는 것이다.
이에 대해서 인증 요청을 만들 수 있다.
근데 기본적으로는 익명의 요청을 다 받아들이도록 돼있다.
ㄷㄷ 진짜?
보통 쿠버네티스 공급자는 여기에 웹훅과 인증서 로직을 부여한다.
그렇게 node에 대한 적절한 권한을 가지고 있음을 보장한다.

완화책은 다음과 같다.

ETCD api

Etcd는 tcp 2379포트를 열고 데이터베이스로서 기능한다.
여기에 접근 가능한 것은 api 서버와, 백업 툴 뿐이다.
여기에 접근하면 진짜 클러스터의 모든 것을 조작할 수 있는 거라 엄청 위험한 것이다.
이 api로의 접근은 클라이언트 인증서 인증을 통해 이뤄진다.
이 인증만 되면 완전 권한을 얻게 된다.
여기에 세밀한 인가 제어가 없어서, 사실 상태 체크만 할 생각으로 만든 인증서라도 사실 모든 권한을 얻는다.
근데 이 api로 또 직접 접근하는 건 아무런 감사에 걸리지 않는다.
이거 털리면 그냥 클러스터는 동물의 숲이 된다!

많은 공급자는 여기에 mtls를 적용한다.
그래서 etcd으로의 접근하는 클라이언트도 인증이 되도록 한다.

완화책은 다음과 같다.

컨테이너 런타임 소켓

컨테이너 런타임에 직접 접근하는 방법도 당연히 api 서버를 우회한다.
Podman 정도만 빼면, 웬만한 모든 컨테이너 런타임이 UNIX 소켓으로 데몬을 노출하고 있다.
kubelet이 런타임에 접근하는 경로도 이것이다.
이 경로를 탈취 당한다는 것은, 한 노드만의 문제가 아닐 수 있다.
해당 노드에 시크릿이 보관되었다면, 이 정보를 탈취할 가능성이 생기며 이를 통해 다른 노드로의 침투도 가능해질 여지가 생긴다.

완화책은 다음과 같다.

관련 문서

이름 noteType created

참고